package com.ojoin.trade.common.web.shiro;

import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import com.ojoin.trade.common.autoconfig.api.IChangeListener;
import com.ojoin.trade.common.autoconfig.api.IConfig;
import com.ojoin.trade.common.utils.IpUtils;
import com.ojoin.trade.common.utils.LogUtils;

@Service
public class IPFilter extends AuthorizationFilter implements IChangeListener {
	
	private static final  Logger log = LoggerFactory.getLogger(AuthorizationFilter.class);
	
	public static final Pattern IPV4_PATTERN = Pattern
			.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
	Set<String> authorizedIps = Sets.newConcurrentHashSet();
	Set<String> deniedIps = Sets.newConcurrentHashSet();
	
	
	private   void loadConfig(IConfig config) {
		setAuthorizedIps(config.get("authorizedIps","127.0.0.1,123.126.20.106"));
    }
	
	
	public void setAuthorizedIps(String authorizedIps) {
		if (!(StringUtils.hasText(authorizedIps))) {
			throw new IllegalArgumentException(
					"authorizedHosts argument cannot be null or empty.");
		}
		
		List<String> ips=Splitter.on(",").trimResults().omitEmptyStrings().splitToList(authorizedIps);
		this.authorizedIps.clear();
		for (String ip : ips) {
			if (IPV4_PATTERN.matcher(ip).matches())
				this.authorizedIps.add(ip);
		}
	}

	public void setDeniedIps(String deniedIps) {
		if (!(StringUtils.hasText(deniedIps)))
			throw new IllegalArgumentException(
					"deniedHosts argument cannot be null or empty.");
	}

	protected boolean isIpv4Candidate(String host) {
		String[] quads = StringUtils.tokenizeToStringArray(host, ".");
		if ((quads == null) || (quads.length != 4)) {
			return false;
		}
		for (String quad : quads) {	
			try {
				Integer.parseInt(quad);
			} catch (NumberFormatException nfe) {
				return false;
			}
		}

		return true;
	}

	protected boolean isAccessAllowed(ServletRequest request,
			ServletResponse response, Object mappedValue) throws Exception {
		
		String accessIp = IpUtils.getIpAddr((HttpServletRequest) request);
		
		
		LogUtils.info(log,"AccessIp %s , authorizedIps %s",accessIp,authorizedIps);
		
		if(isIpv4Candidate(accessIp)){
		
			if (deniedIps.contains(accessIp)){
				return  false;
			}
			
			if (authorizedIps.contains(accessIp)) {
				return true;
			}
		
		}
		return false;
	}


	protected boolean onAccessDenied(ServletRequest request,
			ServletResponse response) throws IOException {

        WebUtils.toHttp(response).sendError(HttpServletResponse.SC_FORBIDDEN);

		return false;
	}
	@Override
	public void changed(IConfig config) {
		 loadConfig(config);
	}
}